#!/usr/bin/python2
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t -*-

import abc
from ass_util import AssUtil


class Input(abc.ABC):

    def __init__(self, data):
        self._id = AssUtil.dictGetAndDel(data, "id")

        self._timestamp = AssUtil.dictGetAndDel(data, "start_timestamp")

        self._confidence = AssUtil.dictGetAndDel(data, "confidence", 10)
        assert 0 < self._confidence <= 10

        self._explain = AssUtil.dictGetAndDel("explaination", None)

    @property
    def id(self):
        return self._id

    @property
    def start_timestamp(self):
        return self._timestamp

    @property
    def confidence(self):
        return self._confidence

    @property
    def explaination(self):
        return self._explain


class InputIntent(Input):

    """
    This object represents that a source wants something from me.
    The source can be human, animal, another partner or any other type of instance.
    The intent can be analyzed from voice, body gesture, brain-computer interface, even telepathy or magic.
    Intent can change. For example, "<id:3a4b> openLight starts from 11:00:30" at 11:01:00 may change to "<id:3a4b> openLamp starts from 11:00:20" at 11:02:00.
    Generally, I should do something for the intent, maybe fulfill it, maybe reject it, or maybe ignore it.
    Properties:
        intent + parameters:  Structured data describes the intent.
        source:               A knowledge that describes the source instance.
        start_timestamp:      Represents how long this intent lasts.
        confidence:      
        explaination:         Contains how this intent is analysed out, for debugging only.
    """

    def __init__(self, data):
        data = data.copy()
        super().__init__(data)
        self._intent = data["intent"]
        self._parameters = data.get("parameters", {})
        self._source = data["source"]

    @property
    def itent(self):
        return self._intent

    @property
    def parameters(self):
        return self._parameters

    @property
    def source(self):
        return self._source


class InputSaying(Input):

    """
    This object means that I get to know that a source says something in language.
    The source can be anything that outputs language, the language must be able to be represented by text.
    Saying can change. For example, "<id:3a4b> 'Have me' starts from 11:00:10" at 11:00:11 may change to "<id:3a4b> 'Hey, get me a pen.' starts from 11:00:09" at 11:11:12.
    Properties:
        text:            
        source:          A knowledge that describes the source instance.
        is_to_me:        True means that I know exactly that the source is saying to me. For example through text input widget, or wakeup word.
                         False means that I don't know or I'm not sure, maybe saying to me, maybe to others, or maybe only soliloquizing.
        start_timestamp: Represents how long this saying lasts.
        confidence:      Will be 10 if the text is input from like a text input widget.
                         Or be some value if the text is anaylzed from something such as human voice or OCR.
        explaination:    
    """

    def __init__(self, data):
        data = data.copy()
        super().__init__(data)
        self._text = data["text"]
        self._source = data["source"]
        self._bToMe = data["is_to_me"]

    @property
    def text(self):
        return self._text

    @property
    def source(self):
        return self._source

    @property
    def is_to_me(self):
        return self._bToMe


class InputImage(Input):

    """
    This object means that a source shows me an image.
    Image won't change. That's intuitive. But one source can show multiple images simutaneously.
    Image won't last. It can be understood as the image only shown to me for a moment and then taken back. It's enough for me to response to it, I can remember it if neccessary.
    Properties:
        image:            
        source:          A knowledge that describes the source instance.
        start_timestamp: The moment that the image is shown to me.
        confidence:      Always be 10.
        explaination:    Always be None.
    """

    def __init__(self, data):
        data = data.copy()
        super().__init__(data)
        self._image = data["image"]
        self._source = data["source"]

    @property
    def image(self):
        return self._image

    @property
    def source(self):
        return self._source


class InputMedia(Input):

    """
    This object means that a source shows me a piece of media.
    Media won't change. That's intuitive. But one source can show multiple pieces of media simutaneously.
    Media won't last. Of course media lasts for some time. It can be understood as the media only shown to me for once.
    Properties:
        source:          A knowledge that describes the source instance.
        start_timestamp: The moment that the video starts for me.
        confidence:      Always be 10.
        explaination:    Always be None.
    """

    def __init__(self, data):
        data = data.copy()
        super().__init__(data)
        self._data = AssUtil.dictGetAndDel(data, "source")

    # video
    # audio
    # 3d-data

    @property
    def data(self):
        return self._data


class InputUserSessionState(Input):

    """
    This object contains all aspects of a user session state, in a period of time, until now.
    UserSessionState won't change. Multiple UserSessionState won't overlap by time.
    Properties:
        uid:             Id of the session's owner.
        start_timestamp: Represents when this state stream starts.
        confidence:      Always be 10.
        explaination:    Always be None.
    """

    def __init__(self, data):
        data = data.copy()          # FIXME: need to deal with streams
        super().__init__(data)
        self._uid = AssUtil.dictGetAndDel(data, "uid")
        self._data = data

    @property
    def uid(self):
        return self._uid

    # snoop					snoop user's operation (keyboard/mouse)
    # seat
    # screen

    @property
    def data(self):
        return self._data


class InputSystemState(Input):

    """
    This object contains all aspects of system state, in a period of time, until now.
    SystemState won't change. Multiple SystemState won't overlap by time.
    Properties:
        start_timestamp: Represents when this state stream starts.
        confidence:      Always be 10.
        explaination:    Always be None.
    """

    def __init__(self, data):
        data = data.copy()          # FIXME: need to deal with streams
        super().__init__(data)
        self._data = data

    # geolocation				get geolocation information
    # datetime					get datetime information
    # network-access			get network-access information

    @property
    def data(self):
        return self._data


class InputCliScriptEcho(Input):

    """
    This object represents the echo and return code of a executed script.
    I "act" only in this way (contrary to "express").
    All interactions are in this script.
    Only Linux script is supported.
    Properties:
        start_timestamp: Represents when this echo starts.
        confidence:      Always be 10.
        explaination:    Always be None.

    """

    def __init__(self, data):
        data = data.copy()          # FIXME: need to deal with streams
        super().__init__(data)
        self._data = data

        self._bSystemSession = system_or_session
        self._scriptContent = script_content

    @property
    def system_or_session(self):
        return self._bSystemSession

    @property
    def script_content(self):
        return self._scriptContent




class Output(abc.ABC):
    pass


class OuputIntent(Output):

    """
    This object represents that I want something from a specific target.
    This object is used for interacting with other AI instance. So no "expressing" is needed, it's the most efficient.
    Multiple output objects should be sent if I'm wanting from multiple AI instances.
    Properties:
        intent + parameters:  Structured data describes the intent.
        target:               Target id.
    """

    def __init__(self, intent, parameters, target):
        self._intent = intent
        self._parameters = parameters
        self._target = target

    @property
    def itent(self):
        return self._intent

    @property
    def parameters(self):
        return self._parameters

    @property
    def target(self):
        return self._target


class OutputSaying(Output):

    """
    This object means that I express in language to specific target.
    There can be no text but only attitude! Trigger should preform a reasonable action.
    There's always a clear target. Triger should decide how to do.
    Properties:
        text:            What to say. Can be empty string.
        attitude:        A knowledge that describes my attitude (body language) when saying.
        target:          Target id.
    """

    def __init__(self, text, attitude, target):
        self._text = text
        self._attitude = attitude
        self._target = target

    @property
    def text(self):
        return self._text

    @property
    def attitude(self):
        return self._attitude

    @property
    def target(self):
        return self._target


class OutputImage(Output):

    """
    This object means that I draw and show a image to a specific target.
    There's always a clear target. Triger should decide how to do.
    Properties:
        image:            
        target:               Target id.
    """

    def __init__(self, image, target):
        self._image = image
        self._target = target

    @property
    def image(self):
        return self._image

    @property
    def target(self):
        return self._target


class OutputMedia(Output):

    """
    This object means that I create and show a piece of media to a specific target.
    There's always a clear target. Triger should decide how to do.
    Properties:
        target:               Target id.
    """

    def __init__(self, data, target):
        self._data = data
        self._target = target

    # video
    # audio
    # 3d-data

    @property
    def data(self):
        return self._data


class OutputCliScript(Output):

    """
    This object means that I write a script and execute it in user's session.
    I "act" only in this way (contrary to "express").
    All interactions are in this script.
    Only Linux script is supported.
    Properties:

    """

    def __init__(self, id, system_or_session, script_content, monitor_type):
        self._id = id
        self._bSystemSession = system_or_session
        self._scriptContent = script_content

    @property
    def id(self):
        return self._id

    @property
    def system_or_session(self):
        return self._bSystemSession

    @property
    def script_content(self):
        return self._scriptContent


class OutputGuiSessionOperation(Output):
    pass

